﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;

namespace AWLoadTesterLibrary
{
    /// <summary>
    /// Observable application options for the WPF GUI.
    /// </summary>
    public class LoadTestRunOptions : INotifyPropertyChanged
    {
        /// <summary>
        /// Property changed event for the INotifyPropertyChanged class.  Thrown when a property changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = null;

        private string uRL;
        /// <summary>
        /// The test URL to be accessed this session.
        /// </summary>
        public string URL
        {
            get
            {
                return uRL;
            }

            set
            {
                if (uRL != value)
                {
                    uRL = value;
                    OnPropertyChanged("URL");
                }
            }
        }

        private string outputFile;
        /// <summary>
        /// The file that stores the statistics in XML format.
        /// </summary>
        public string OutputFile
        {
            get
            {
                return outputFile;
            }

            set
            {
                if (outputFile != value)
                {
                    outputFile = value;
                    OnPropertyChanged("OutputFile");
                }
            }
        }

        private string conConnections;
        /// <summary>
        /// The number of simultaneous connections the "browser" can make this session.
        /// <para>Regular browsers usually make 2-10 of those at a time</para>
        /// </summary>
        public string ConConnections
        {
            get
            {
                return conConnections;
            }

            set
            {
                if (conConnections != value)
                {
                    conConnections = value;
                    OnPropertyChanged("ConConnections");
                }
            }
        }

        private string usersMin;
        /// <summary>
        /// The number of users we generate per minute.  Each user is spawn on their own thread.
        /// </summary>
        public string UsersMin
        {
            get
            {
                return usersMin;
            }

            set
            {
                if (usersMin != value)
                {
                    usersMin = value;
                    OnPropertyChanged("UsersMin");
                }
            }
        }

        private bool showBrowser;
        /// <summary>
        /// Whether to show the embedded browser or not.  This can be used for additional statistics
        /// </summary>
        public bool ShowBrowser
        {
            get
            {
                return showBrowser;
            }

            set
            {
                if (showBrowser != value)
                {
                    showBrowser = value;
                    OnPropertyChanged("ShowBrowser");
                }
            }
        }

        private string browseTime;
        /// <summary>
        /// A random pause maximum between accessing pages.  Normally this should be under ten seconds
        /// </summary>
        public string BrowseTime
        {
            get
            {
                return browseTime;
            }

            set
            {
                if (browseTime != value)
                {
                    browseTime = value;
                    OnPropertyChanged("BrowseTime");
                }
            }
        }

        private string testTime;
        /// <summary>
        /// The number of minutes the test should be run.
        /// </summary>
        /// <example>If you specified 10 users in "UserMin" and 5 minutes in "TestTime", you would have generated 50 users.</example>
        public string TestTime
        {
            get
            {
                return testTime;
            }

            set
            {
                if (testTime != value)
                {
                    testTime = value;
                    OnPropertyChanged("TestTime");
                }
            }
        }

        private string currentTime;
        /// <summary>
        /// Elapsed time of the current test run
        /// </summary>
        public string CurrentTime
        {
            get
            {
                return currentTime;
            }

            set
            {
                if (currentTime != value)
                {
                    currentTime = value;
                    OnPropertyChanged("CurrentTime");
                }
            }
        }

        private string threadCount;
        /// <summary>
        /// The number of threads currently running.  When no tests are running this should be 1.
        /// </summary>
        public string ThreadCount
        {
            get
            {
                return threadCount;
            }

            set
            {
                if (threadCount != value)
                {
                    threadCount = value;
                    OnPropertyChanged("ThreadCount");
                }
            }
        }

        private string logText;
        /// <summary>
        /// LogText for the front end.
        /// </summary>
        public string LogText
        {
            get
            {
                return logText;
            }

            set
            {
                if (logText != value)
                {
                    logText = value;
                    OnPropertyChanged("LogText");
                }
            }
        }

        private List<Thread> threadList;
        /// <summary>
        /// The list of threads currently running.  When no tests are running this should be empty.
        /// <para>
        /// Note: This list is accessed across threads.  The main GUI thread uses it to count the outstanding tests.
        /// </para>
        /// </summary>
        public List<Thread> ThreadList
        {
            get
            {
                return threadList;
            }

            set
            {
                if (threadList != value)
                {
                    threadList = value;
                    OnPropertyChanged("ThreadList");
                }
            }
        }

        /// <summary>
        /// Called when a property changes to notify WPF
        /// </summary>
        /// <param name="PropName">The name of the property beiing changed.</param>
        protected virtual void OnPropertyChanged(string PropName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(PropName));
            }
        }

        /// <summary>
        /// Timer for counting elapsed time during an active test.  This is displayed to the frontend.
        /// </summary>
        public System.Timers.Timer TestTimer { get; set; }

        /// <summary>
        /// Tracks the start time of the active test
        /// </summary>
        private DateTime TestStartTime { get; set; }

        /// <summary>
        /// Create a new run options object
        /// </summary>
        public LoadTestRunOptions()
        {
            logText = "";
        }

        /// <summary>
        /// Starts the test timer when a job starts.  Updates the "CurrentTime" member with the current elapsed time.
        /// </summary>
        /// <see cref="CurrentTime"/>
        /// <see cref="StopTestTimer"/>
        public void StartTestTimer()
        {
            TestStartTime = DateTime.UtcNow;
            TestTimer = new System.Timers.Timer();
            TestTimer.Enabled = true;
            TestTimer.Interval = 1000;
            TestTimer.Elapsed += new System.Timers.ElapsedEventHandler((s, e) =>
            {
                TimeSpan currSpan = DateTime.UtcNow.Subtract(TestStartTime);
                CurrentTime = String.Format("{0:00}:{1:00}:{2:00}", currSpan.Hours, currSpan.Minutes, currSpan.Seconds); //.ToString(@"hh\:mm\:ss");
            });
            TestTimer.Start();
        }

        /// <summary>
        /// Stops the elapsed test time timer
        /// </summary>
        /// <see cref="StartTestTimer"/>
        public void StopTestTimer()
        {
            if (TestTimer != null)
            {
                TestTimer.Stop();
            }

            TestTimer = null;
        }

        /// <summary>
        /// Reads in all the values from the registry
        /// </summary>
        /// <param name="reg"></param>
        public void Read(RegistryUtil reg)
        {
            URL = reg.URL;
            OutputFile = reg.OutputFile;

            TestTime = reg.TestTime.ToString();
            BrowseTime = reg.BrowseTime.ToString();
            ConConnections = reg.ConConnections.ToString();
            UsersMin = reg.UserMins.ToString();
            ShowBrowser = reg.ShowBrowser!=0?true:false;
        }

        /// <summary>
        /// Writes all the options into the registry
        /// </summary>
        /// <param name="reg"></param>
        public void Write(RegistryUtil reg)
        {
            reg.URL = URL;
            reg.OutputFile = OutputFile;

            int tempInt = 0;
            if (Int32.TryParse(TestTime, out tempInt))
            {
                reg.TestTime = tempInt;
            }

            tempInt = 0;
            if (Int32.TryParse(BrowseTime, out tempInt))
            {
                reg.BrowseTime = tempInt;
            }

            tempInt = 0;
            if (Int32.TryParse(ConConnections, out tempInt))
            {
                reg.ConConnections = tempInt;
            }

            tempInt = 0;
            if (Int32.TryParse(UsersMin, out tempInt))
            {
                reg.UserMins = tempInt;
            }

            reg.ShowBrowser = ShowBrowser ? 1 : 0;
        }
    }

}
